Move custom-build-related code in its own module
authorPierre Krieger <pierre.krieger1708@gmail.com>
Tue, 28 Oct 2014 13:22:02 +0000 (14:22 +0100)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 5 Nov 2014 19:37:34 +0000 (11:37 -0800)
src/cargo/ops/cargo_rustc/custom_build.rs [new file with mode: 0644]
src/cargo/ops/cargo_rustc/mod.rs

diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs
new file mode 100644 (file)
index 0000000..1fb19f7
--- /dev/null
@@ -0,0 +1,198 @@
+use std::io::{fs, BufferedReader, BufReader, USER_RWX};
+use std::io::fs::{File, PathExtensions};
+
+use core::{Package, Target};
+use util::{CargoResult, CargoError, human};
+use util::{internal, ChainError};
+
+use super::job::Work;
+use super::{process, KindHost, Context};
+
+/// Prepares a `Work` that executes the target as a custom build script.
+pub fn prepare_execute_custom_build(pkg: &Package, target: &Target,
+                                cx: &mut Context)
+                                -> CargoResult<Work> {
+    let layout = cx.layout(pkg, KindHost);
+    let script_output = layout.build(pkg);
+    let build_output = layout.build_out(pkg);
+
+    // Building the command to execute
+    let to_exec = try!(cx.target_filenames(target))[0].clone();
+    let to_exec = script_output.join(to_exec);
+
+    // Filling environment variables
+    let profile = target.get_profile();
+    let mut p = process(to_exec, pkg, cx)
+                     .env("OUT_DIR", Some(&build_output))
+                     .env("CARGO_MANIFEST_DIR", Some(pkg.get_manifest_path()
+                                                     .display().to_string()))
+                     .env("NUM_JOBS", profile.get_codegen_units().map(|n| n.to_string()))
+                     .env("TARGET", Some(cx.target_triple()))
+                     .env("DEBUG", Some(profile.get_debug().to_string()))
+                     .env("OPT_LEVEL", Some(profile.get_opt_level().to_string()))
+                     .env("PROFILE", Some(profile.get_env()));
+
+    match cx.resolve.features(pkg.get_package_id()) {
+        Some(features) => {
+            for feat in features.iter() {
+                let feat = feat.as_slice().chars()
+                               .map(|c| c.to_uppercase())
+                               .map(|c| if c == '-' {'_'} else {c})
+                               .collect::<String>();
+                p = p.env(format!("CARGO_FEATURE_{}", feat).as_slice(), Some("1"));
+            }
+        }
+        None => {}
+    }
+
+    // building the list of all possible `build/$pkg/output` files
+    // whether they exist or not will be checked during the work
+    let command_output_files = {
+        let layout = cx.layout(pkg, KindHost);
+        cx.dep_targets(pkg).iter().map(|&(pkg, _)| {
+            layout.build(pkg).join("output")
+        }).collect::<Vec<_>>()
+    };
+
+    // Building command
+    let pkg = pkg.to_string();
+    let work = proc(desc_tx: Sender<String>) {
+        desc_tx.send_opt(build_output.display().to_string()).ok();
+
+        if !build_output.exists() {
+            try!(fs::mkdir(&build_output, USER_RWX)
+                .chain_error(|| {
+                    internal("failed to create build output directory for build command")
+                }))
+        }
+
+        // loading each possible custom build output file in order to get their metadata
+        let _metadata = {
+            let mut metadata = Vec::new();
+
+            for flags_file in command_output_files.into_iter() {
+                match File::open(&flags_file) {
+                    Ok(flags) => {
+                        let flags = try!(CustomBuildCommandOutput::parse(
+                            BufferedReader::new(flags), pkg.as_slice()));
+                        metadata.extend(flags.metadata.into_iter());
+                    },
+                    Err(_) => ()  // the file doesn't exist, probably means that this pkg
+                                  // doesn't have a build command
+                }
+            }
+
+            metadata
+        };
+
+        // TODO: ENABLE THIS CODE WHEN `links` IS ADDED
+        /*let mut p = p;
+        for (key, value) in metadata.into_iter() {
+            p = p.env(format!("DEP_{}_{}", PUT LINKS VALUES HERE, value), value);
+        }*/
+
+        let output = try!(p.exec_with_output().map_err(|mut e| {
+            e.msg = format!("Failed to run custom build command for `{}`\n{}",
+                            pkg, e.msg);
+            e.mark_human()
+        }));
+
+        // parsing the output of the custom build script to check that it's correct
+        try!(CustomBuildCommandOutput::parse(BufReader::new(output.output.as_slice()),
+                                             pkg.as_slice()));
+
+        // writing the output to the right directory
+        try!(fs::File::create(&script_output.join("output")).write(output.output.as_slice())
+            .map_err(|e| {
+                human(format!("failed to write output of custom build command: {}", e))
+            }));
+
+        Ok(())
+    };
+
+    Ok(work)
+}
+
+/// Contains the parsed output of a custom build script.
+pub struct CustomBuildCommandOutput {
+    /// Paths to pass to rustc with the `-L` flag
+    pub library_paths: Vec<Path>,
+    /// Names and link kinds of libraries, suitable for the `-l` flag
+    pub library_links: Vec<String>,
+    /// Metadata to pass to the immediate dependencies
+    pub metadata: Vec<(String, String)>,
+}
+
+impl CustomBuildCommandOutput {
+    // Parses the output of a script.
+    // The `pkg_name` is used for error messages.
+    pub fn parse<B: Buffer>(mut input: B, pkg_name: &str) -> CargoResult<CustomBuildCommandOutput> {
+        let mut library_paths = Vec::new();
+        let mut library_links = Vec::new();
+        let mut metadata = Vec::new();
+
+        for line in input.lines() {
+            // unwrapping the IoResult
+            let line = try!(line.map_err(|e| human(format!("Error while reading\
+                                                            custom build output: {}", e))));
+
+            let mut iter = line.as_slice().splitn(1, |c: char| c == ':');
+            if iter.next() != Some("cargo") {
+                // skip this line since it doesn't start with "cargo:"
+                continue;
+            }
+            let data = match iter.next() {
+                Some(val) => val,
+                None => continue
+            };
+
+            // getting the `key=value` part of the line
+            let mut iter = data.splitn(1, |c: char| c == '=');
+            let key = iter.next();
+            let value = iter.next();
+            let (key, value) = match (key, value) {
+                (Some(a), Some(b)) => (a, b),
+                // line started with `cargo:` but didn't match `key=value`
+                _ => return Err(human(format!("Wrong output for the custom\
+                                               build script of `{}`:\n`{}`", pkg_name, line)))
+            };
+
+            if key == "rustc-flags" {
+                // TODO: some arguments (like paths) may contain spaces
+                let mut flags_iter = value.words();
+                loop {
+                    let flag = match flags_iter.next() {
+                        Some(f) => f,
+                        None => break
+                    };
+                    if flag != "-l" && flag != "-L" {
+                        return Err(human(format!("Only `-l` and `-L` flags are allowed \
+                                                 in build script of `{}`:\n`{}`",
+                                                 pkg_name, value)))
+                    }
+                    let value = match flags_iter.next() {
+                        Some(v) => v,
+                        None => return Err(human(format!("Flag in rustc-flags has no value\
+                                                          in build script of `{}`:\n`{}`",
+                                                          pkg_name, value)))
+                    };
+                    match flag {
+                        "-l" => library_links.push(value.to_string()),
+                        "-L" => library_paths.push(Path::new(value)),
+
+                        // was already checked above
+                        _ => return Err(human("only -l and -L flags are allowed"))
+                    };
+                }
+            } else {
+                metadata.push((key.to_string(), value.to_string()))
+            }
+        }
+
+        Ok(CustomBuildCommandOutput {
+            library_paths: library_paths,
+            library_links: library_links,
+            metadata: metadata,
+        })
+    }
+}
index 014cc2f5c7543e7e14d07116d35e40cfd54e4367..65db067d4f083b891018fbc246adb068a5686cea 100644 (file)
@@ -1,6 +1,6 @@
 use std::collections::HashSet;
 use std::dynamic_lib::DynamicLibrary;
-use std::io::{fs, BufferedReader, BufReader, USER_RWX};
+use std::io::{fs, BufferedReader, USER_RWX};
 use std::io::fs::{File, PathExtensions};
 use std::os;
 
@@ -8,6 +8,7 @@ use core::{SourceMap, Package, PackageId, PackageSet, Target, Resolve};
 use util::{mod, CargoResult, ProcessBuilder, CargoError, human, caused_human};
 use util::{Require, Config, internal, ChainError, Fresh, profile, join_paths};
 
+use self::custom_build::CustomBuildCommandOutput;
 use self::job::{Job, Work};
 use self::job_queue as jq;
 use self::job_queue::JobQueue;
@@ -20,6 +21,7 @@ pub use self::layout::{Layout, LayoutProxy};
 
 mod context;
 mod compilation;
+mod custom_build;
 mod fingerprint;
 mod job;
 mod job_queue;
@@ -180,8 +182,9 @@ fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
                         (old_build, script_output)
                     };
 
-                    let execute_cmd = try!(prepare_execute_custom_build(pkg,
-                                                                        target, cx));
+                    let execute_cmd = try!(custom_build::prepare_execute_custom_build(pkg,
+                                                                                      target,
+                                                                                      cx));
 
                     // building a `Work` that creates the directory where the compiled script
                     // must be placed
@@ -342,195 +345,6 @@ fn compile_custom_old(pkg: &Package, cmd: &str,
     })
 }
 
-// Contains the parsed output of a custom build script.
-struct CustomBuildCommandOutput {
-    // paths to pass to rustc with the `-L` flag
-    library_paths: Vec<Path>,
-    // names and link kinds of libraries, suitable for the `-l` flag
-    library_links: Vec<String>,
-    // metadata to pass to the immediate dependencies
-    metadata: Vec<(String, String)>,
-}
-
-impl CustomBuildCommandOutput {
-    // Parses the output of a script.
-    // The `pkg_name` is used for error messages.
-    fn parse<B: Buffer>(mut input: B, pkg_name: &str) -> CargoResult<CustomBuildCommandOutput> {
-        let mut library_paths = Vec::new();
-        let mut library_links = Vec::new();
-        let mut metadata = Vec::new();
-
-        for line in input.lines() {
-            // unwrapping the IoResult
-            let line = try!(line.map_err(|e| human(format!("Error while reading\
-                                                            custom build output: {}", e))));
-
-            let mut iter = line.as_slice().splitn(1, |c: char| c == ':');
-            if iter.next() != Some("cargo") {
-                // skip this line since it doesn't start with "cargo:"
-                continue;
-            }
-            let data = match iter.next() {
-                Some(val) => val,
-                None => continue
-            };
-
-            // getting the `key=value` part of the line
-            let mut iter = data.splitn(1, |c: char| c == '=');
-            let key = iter.next();
-            let value = iter.next();
-            let (key, value) = match (key, value) {
-                (Some(a), Some(b)) => (a, b),
-                // line started with `cargo:` but didn't match `key=value`
-                _ => return Err(human(format!("Wrong output for the custom\
-                                               build script of `{}`:\n`{}`", pkg_name, line)))
-            };
-
-            if key == "rustc-flags" {
-                // TODO: some arguments (like paths) may contain spaces
-                let mut flags_iter = value.words();
-                loop {
-                    let flag = match flags_iter.next() {
-                        Some(f) => f,
-                        None => break
-                    };
-                    if flag != "-l" && flag != "-L" {
-                        return Err(human(format!("Only `-l` and `-L` flags are allowed \
-                                                 in build script of `{}`:\n`{}`",
-                                                 pkg_name, value)))
-                    }
-                    let value = match flags_iter.next() {
-                        Some(v) => v,
-                        None => return Err(human(format!("Flag in rustc-flags has no value\
-                                                          in build script of `{}`:\n`{}`",
-                                                          pkg_name, value)))
-                    };
-                    match flag {
-                        "-l" => library_links.push(value.to_string()),
-                        "-L" => library_paths.push(Path::new(value)),
-
-                        // was already checked above
-                        _ => return Err(human("only -l and -L flags are allowed"))
-                    };
-                }
-            } else {
-                metadata.push((key.to_string(), value.to_string()))
-            }
-        }
-
-        Ok(CustomBuildCommandOutput {
-            library_paths: library_paths,
-            library_links: library_links,
-            metadata: metadata,
-        })
-    }
-}
-
-// Prepares a `Work` that executes the target as a custom build script.
-fn prepare_execute_custom_build(pkg: &Package, target: &Target,
-                                cx: &mut Context)
-                                -> CargoResult<Work> {
-    let layout = cx.layout(pkg, KindHost);
-    let script_output = layout.build(pkg);
-    let build_output = layout.build_out(pkg);
-
-    // Building the command to execute
-    let to_exec = try!(cx.target_filenames(target))[0].clone();
-    let to_exec = script_output.join(to_exec);
-
-    // Filling environment variables
-    let profile = target.get_profile();
-    let mut p = process(to_exec, pkg, cx)
-                     .env("OUT_DIR", Some(&build_output))
-                     .env("CARGO_MANIFEST_DIR", Some(pkg.get_manifest_path()
-                                                     .display().to_string()))
-                     .env("NUM_JOBS", profile.get_codegen_units().map(|n| n.to_string()))
-                     .env("TARGET", Some(cx.target_triple()))
-                     .env("DEBUG", Some(profile.get_debug().to_string()))
-                     .env("OPT_LEVEL", Some(profile.get_opt_level().to_string()))
-                     .env("PROFILE", Some(profile.get_env()));
-
-    match cx.resolve.features(pkg.get_package_id()) {
-        Some(features) => {
-            for feat in features.iter() {
-                let feat = feat.as_slice().chars()
-                               .map(|c| c.to_uppercase())
-                               .map(|c| if c == '-' {'_'} else {c})
-                               .collect::<String>();
-                p = p.env(format!("CARGO_FEATURE_{}", feat).as_slice(), Some("1"));
-            }
-        }
-        None => {}
-    }
-
-    // building the list of all possible `build/$pkg/output` files
-    // whether they exist or not will be checked during the work
-    let command_output_files = {
-        let layout = cx.layout(pkg, KindHost);
-        cx.dep_targets(pkg).iter().map(|&(pkg, _)| {
-            layout.build(pkg).join("output")
-        }).collect::<Vec<_>>()
-    };
-
-    // Building command
-    let pkg = pkg.to_string();
-    let work = proc(desc_tx: Sender<String>) {
-        desc_tx.send_opt(build_output.display().to_string()).ok();
-
-        if !build_output.exists() {
-            try!(fs::mkdir(&build_output, USER_RWX)
-                .chain_error(|| {
-                    internal("failed to create build output directory for build command")
-                }))
-        }
-
-        // loading each possible custom build output file in order to get their metadata
-        let _metadata = {
-            let mut metadata = Vec::new();
-
-            for flags_file in command_output_files.into_iter() {
-                match File::open(&flags_file) {
-                    Ok(flags) => {
-                        let flags = try!(CustomBuildCommandOutput::parse(
-                            BufferedReader::new(flags), pkg.as_slice()));
-                        metadata.extend(flags.metadata.into_iter());
-                    },
-                    Err(_) => ()  // the file doesn't exist, probably means that this pkg
-                                  // doesn't have a build command
-                }
-            }
-
-            metadata
-        };
-
-        // TODO: ENABLE THIS CODE WHEN `links` IS ADDED
-        /*let mut p = p;
-        for (key, value) in metadata.into_iter() {
-            p = p.env(format!("DEP_{}_{}", PUT LINKS VALUES HERE, value), value);
-        }*/
-
-        let output = try!(p.exec_with_output().map_err(|mut e| {
-            e.msg = format!("Failed to run custom build command for `{}`\n{}",
-                            pkg, e.msg);
-            e.mark_human()
-        }));
-
-        // parsing the output of the custom build script to check that it's correct
-        try!(CustomBuildCommandOutput::parse(BufReader::new(output.output.as_slice()),
-                                             pkg.as_slice()));
-
-        // writing the output to the right directory
-        try!(fs::File::create(&script_output.join("output")).write(output.output.as_slice())
-            .map_err(|e| {
-                human(format!("failed to write output of custom build command: {}", e))
-            }));
-
-        Ok(())
-    };
-
-    Ok(work)
-}
-
 fn rustc(package: &Package, target: &Target,
          cx: &mut Context, req: PlatformRequirement)
          -> CargoResult<Vec<(Work, Kind)> >{